/* 
 * Copyright 2010 Ziya Guven Koylu, Ozge Koylu
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.koylu.caffein.model.handler;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javassist.util.proxy.MethodHandler;

import com.koylu.caffein.model.caffein.CaffeinConfig;
import com.koylu.caffein.model.clazz.Clazz;
import com.koylu.caffein.query.Query;
import com.koylu.caffein.query.filter.CompositeFilter;
import com.koylu.caffein.query.group.Group;
import com.koylu.caffein.query.join.Join;
import com.koylu.caffein.query.order.Order;
import com.koylu.caffein.query.target.Target;

public class QueryPropertyContainerHandler implements MethodHandler{
	
	private CaffeinConfig caffeinConfig;
	private Clazz clazz;
	private Object object;
	private String alias;
	private List<Join> joins;
	private CompositeFilter compositeFilter;
    private List<Order> orders;
    private List<Group> groups;
    private Target target;
    private int firstResult;
    private int maxResult;
	private Query query;
	private Object value;
	private Integer count;
	
	public QueryPropertyContainerHandler(Query query) {
		this.query = query;
	}
	
	public QueryPropertyContainerHandler(CaffeinConfig caffeinConfig, Clazz clazz, Object object, String alias, List<Join> joins, CompositeFilter compositeFilter, List<Order> orders, List<Group> groups, Target target, int firstResult, int maxResult) {
		this.caffeinConfig = caffeinConfig;
		this.clazz = clazz;
		this.object = object;
		this.alias = alias;
		this.joins = joins;
		this.compositeFilter = compositeFilter;
		this.orders = orders;
		this.groups = groups;
		this.target = target;
		this.firstResult = firstResult;
		this.maxResult = maxResult;
	}
	
	public Object invoke(Object object, Method method, Method proceed, Object[] args) throws Throwable {
		String methodName = method.getName();
		if ("getQuery".equals(methodName)) {
			if(query == null){
				prepareQuery();
			}
			return query;
		}else if("getCount".equals(methodName)){
			if(count == null){
				if(query == null){
					prepareQuery();
				}
				count = query.count();
			}
			return count;
		}else if("getValue".equals(methodName)){
			if(value == null){
				if(query == null){
					prepareQuery();
				}
				value = query.collection(ArrayList.class);
				if(((List<?>)value).size() == 1){
					value =((List<?>)value).get(0);
				}				
			}
		}
		return value;
	}
	
	public void prepareQuery() throws Exception{
		query = caffeinConfig.createQuery(clazz, alias);
		if(compositeFilter != null){
			compositeFilter.resolveValue(object);
			query.setCompositeFilter(compositeFilter);			
		}
		if(joins != null){
			for (Iterator<Join> iterator = joins.iterator(); iterator.hasNext();) {
				query.addJoin(iterator.next());
			}			
		}
		if(orders != null){
			for (Iterator<Order> iterator = orders.iterator(); iterator.hasNext();) {
				query.addOrder(iterator.next());
			}			
		}
		if(groups != null){
			for (Iterator<Group> iterator = groups.iterator(); iterator.hasNext();) {
				query.addGroupBy(iterator.next());
			}
		}
		if(firstResult != -1 && maxResult != -1){
			query.setFirstResult(firstResult);
			query.setMaxResult(maxResult);
		}
		if(target != null){
			query.setTarget(target);			
		}
	}
}